package de.jmda.mview;

import java.awt.Dimension;
import java.awt.Insets;

import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JScrollPane;
import javax.swing.JViewport;

import de.jmda.mview.typeshape.TypeShape;

/**
 * Helper that detects and handles significant events on {@link Typeshape}
 * instances contained by a {@link DesktopPane}.
 * 
 * @author roger.jmda@gmail.com
 */
public class DesktopManager
		extends DesktopManagerBase
{
	//	private final static Logger LOGGER =
	//			Logger.getLogger(DesktopManager.class);
	private DesktopPane desktopPane;

	public DesktopManager(DesktopPane desktopPane)
	{
		super(desktopPane.getDesktopManager());
		this.desktopPane = desktopPane;
	}

	/**
	 * Updates {@link #oldBounds}.
   * @see de.jmda.mview.DesktopManagerBase#beginDraggingFrame(javax.swing.JComponent)
   */
  @Override
  public void beginDraggingFrame(JComponent f)
  {
	  super.beginDraggingFrame(f);
  }

	/**
	 * Updates {@link #oldBounds}.
   * @see de.jmda.mview.DesktopManagerBase#beginResizingFrame(javax.swing.JComponent, int)
   */
  @Override
  public void beginResizingFrame(JComponent f, int direction)
  {
	  super.beginResizingFrame(f, direction);
  }

	/**
	 * Updates {@link #oldBounds}.
	 * Calls {@link #update(JComponent)} to update objects depending on <code>f
	 * </code>.
	 *
	 * @see de.jmda.mview.DesktopManagerBase#dragFrame(javax.swing.JComponent, int, int)
	 */
	@Override
	public void dragFrame(JComponent f, int newX, int newY)
	{
		super.dragFrame(f, newX, newY);
		update(f);
		desktopPane.repaint();
	}

	/**
	 * Updates {@link #oldBounds}.
	 * Calls {@link #update(JComponent)} to update objects depending on <code>f
	 * </code>.
	 *
	 * @see de.jmda.mview.DesktopManagerBase#resizeFrame(javax.swing.JComponent, int, int, int, int)
	 */
	@Override
	public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
	    int newHeight)
	{
		super.resizeFrame(f, newX, newY, newWidth, newHeight);
		update(f);
		desktopPane.repaint();
	}

	/**
	 * Update scrollbars (if available).
	 *
	 * @see de.jmda.mview.DesktopManagerBase#endDraggingFrame(javax.swing.JComponent)
	 */
	@Override
	public void endDraggingFrame(JComponent f)
	{
		super.endDraggingFrame(f);
		resizeDesktop();
	}

	/**
	 * Update scrollbars (if available).
	 *
	 * @see de.jmda.mview.DesktopManagerBase#endResizingFrame(javax.swing.JComponent)
	 */
	@Override
	public void endResizingFrame(JComponent f)
	{
		super.endResizingFrame(f);
		resizeDesktop();
	}

	/**
	 * resize desktop if necessary and thereby update scrollbars (if available)
	 */
	protected void resizeDesktop()
	{
		JScrollPane scrollPane = getScrollPane();

		if (scrollPane == null)
		{
			// type view desktop pane does not seem to live inside a scroll pane
			// nothing else to do here:
			return;
		}

		// calculate necessary size for scroll pane
		int xMin = 0;
		int xMax = 0;
		int yMin = 0;
		int yMax = 0;

		for (JInternalFrame internalFrame : desktopPane.getAllFrames())
		{
			int x = internalFrame.getX();
			int y = internalFrame.getY();

			if (x + internalFrame.getWidth() > xMax)
			{
				xMax = x + internalFrame.getWidth();
			}
			if (x < xMin)
			{
				xMin = x;
			}
			if (y + internalFrame.getHeight() > yMax)
			{
				yMax = y + internalFrame.getHeight();
			}
			if (y < yMin)
			{
				yMin = y;
			}
		}

		// consider insets as well
		Insets scrollInsets = getScrollPaneInsets();

		Dimension d = scrollPane.getVisibleRect().getSize();
		
		if (scrollPane.getBorder() != null)
		{
			d.setSize(
					d.getWidth()  - scrollInsets.left - scrollInsets.right,
			    d.getHeight() - scrollInsets.top  - scrollInsets.bottom);
		}
		
		int newWidth  = xMax;
		int newHeight = yMax;

		// maybe internal frames are located left from or above the visible part of
		// scroll pane
		if (xMin < 0)
		{
			newWidth  = ((int) d.getWidth())  + Math.abs(xMin);
		}
		if (yMin < 0)
		{
			newHeight = ((int) d.getHeight()) + Math.abs(yMin);
		}

		// finally consider scroll bar width and height if necessary
		if (newWidth <= d.getWidth())
		{
			newWidth  = ((int) d.getWidth())  - 20;
		}
		if (newHeight <= d.getHeight())
		{
			newHeight = ((int) d.getHeight()) - 20;
		}

		desktopPane.setAllSize(newWidth, newHeight);

		scrollPane.revalidate();
//		scrollPane.invalidate();
//		scrollPane.validate();
	}

	private JScrollPane getScrollPane()
	{
		if (desktopPane.getParent() instanceof JViewport)
		{
			JViewport viewPort = (JViewport) desktopPane.getParent();

			if (viewPort.getParent() instanceof JScrollPane)
			{
				return (JScrollPane) viewPort.getParent();
			}
		}

		return null;
	}

	private Insets getScrollPaneInsets()
	{
		JScrollPane scrollPane = getScrollPane();
		
		if (scrollPane == null)
		{
			return new Insets(0, 0, 0, 0);
		}
		else
		{
			return getScrollPane().getBorder().getBorderInsets(scrollPane);
		}
	}
	
	/**
	 * Updates objects depending on <code>f</code>.
	 *
	 * @param f
	 */
	private void update(JComponent f)
	{
		if (f instanceof TypeShape<?>)
		{
			desktopPane.update((TypeShape<?>) f);
		}
	}
}